package cn.iocoder.yudao.module.wecom.service.factory;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.wecom.dal.dataobject.apiconfig.WeComApiConfigDO;
import cn.iocoder.yudao.module.wecom.dal.dataobject.providerconfig.WeComProviderConfigDO;
import cn.iocoder.yudao.module.wecom.handler.*;
import cn.iocoder.yudao.module.wecom.service.apiconfig.WeComApiConfigService;
import cn.iocoder.yudao.module.wecom.service.providerconfig.WeComProviderConfigService;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.cp.api.*;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import me.chanjar.weixin.cp.constant.WxCpConsts;
import me.chanjar.weixin.cp.message.WxCpMessageRouter;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.RegEx;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.wecom.enums.ErrorCodeConstants.API_CONFIG_NOT_EXISTS;

@Service
@Valid
@Slf4j
public class CpServiceFactoryImpl implements CpServiceFactory {


    @Resource
    private WeComProviderConfigService weComProviderConfigService;

    @Resource
    private WeComApiConfigService weComApiConfigService;


    private static final Map<String, WxCpService> SERVICE = new ConcurrentHashMap<>();
    private static final Map<String, WxCpMessageRouter> ROUTER = new ConcurrentHashMap<>();

    private static final String msg = "请先配置企业微信相关配置";


    @Override
    public WxCpMessageRouter getWxCpMessageRouter(String target, Long tenantId) {
        String key = "router:" + target + (Objects.nonNull(tenantId) ? ":" + tenantId : "");
        WxCpMessageRouter wxCpMessageRouter = ROUTER.get(key);
        if (ObjectUtil.isEmpty(wxCpMessageRouter)) {
            throw exception(API_CONFIG_NOT_EXISTS);
        }
        return wxCpMessageRouter;
    }

    @Override
    public WxCpService getWxCpService() {
        WxCpService wxCpService = SERVICE.get("service:app");
        if (ObjectUtil.isEmpty(wxCpService)) {
            throw exception(API_CONFIG_NOT_EXISTS);
        }
        return wxCpService;
    }

    @Override
    public WxCpService getWxProviderCpService() {
        WxCpService wxCpService = SERVICE.get("service:provider");
        if (ObjectUtil.isEmpty(wxCpService)) {
            throw exception(API_CONFIG_NOT_EXISTS);
        }
        return wxCpService;
    }

    @Override
    public WxCpService getWxCorpService() {
        WxCpService wxCpService = SERVICE.get("service:corp:" + TenantContextHolder.getTenantId());
        if (ObjectUtil.isEmpty(wxCpService)) {
            throw exception(API_CONFIG_NOT_EXISTS);
        }
        return wxCpService;
    }

    @Override
    @TenantIgnore
    @PostConstruct
    public void refreshService() {
        WeComProviderConfigDO apiConfig = weComProviderConfigService.getProviderConfig();
        if (Objects.nonNull(apiConfig)) {
            reloadConfig(apiConfig);
        }

    }

//    @TenantIgnore
//    @Scheduled(fixedRate = 1, timeUnit = TimeUnit.MINUTES)
//    public void refreshCorpService() {
//        // 加载企业的apiConfig
//        List<WeComApiConfigDO> apiConfigList = weComApiConfigService.getWeComApiConfigList();
//        if (CollUtil.isNotEmpty(apiConfigList)) {
//            reloadConfig(apiConfigList);
//        }
//    }

    public void reloadConfig(List<WeComApiConfigDO> configList) {
        for (WeComApiConfigDO apiConfig : configList) {
            val appConfigStorage = new WxCpDefaultConfigImpl();
            appConfigStorage.setCorpId(apiConfig.getCorpId());
            appConfigStorage.setAccessToken(apiConfig.getAccessToken());
            WxCpService appService = new WxCpServiceImpl();
            appService.setWxCpConfigStorage(appConfigStorage);
            ROUTER.put("router:corp:" + apiConfig.getTenantId(), newRouter(appService));
            SERVICE.put("service:corp:" + apiConfig.getTenantId(), appService);

            log.info("reloadApiConfig: ------ {}", apiConfig);
        }
    }

    public void reloadConfig(WeComProviderConfigDO apiConfig) {
        val appConfigStorage = new WxCpDefaultConfigImpl();
        // 在这里修改了 服务商的id
        appConfigStorage.setCorpId(apiConfig.getSuiteId());
        appConfigStorage.setCorpSecret(apiConfig.getSuiteSecret());
        appConfigStorage.setAesKey(apiConfig.getAesKey());
        appConfigStorage.setToken(apiConfig.getToken());
        WxCpService appService = new WxCpServiceImpl();
        appService.setWxCpConfigStorage(appConfigStorage);
        ROUTER.put("router:app", newRouter(appService));
        SERVICE.put("service:app", appService);

        val providerConfigStorage = new WxCpDefaultConfigImpl();
        // 在这里修改了 服务商的id
        providerConfigStorage.setCorpId(apiConfig.getLoginSuiteId());
        providerConfigStorage.setCorpSecret(apiConfig.getLoginSecret());
        providerConfigStorage.setAesKey(apiConfig.getAesKey());
        providerConfigStorage.setToken(apiConfig.getToken());
        WxCpService providerService = new WxCpServiceImpl();
        providerService.setWxCpConfigStorage(providerConfigStorage);
        ROUTER.put("router:provider", newRouter(providerService));
        SERVICE.put("service:provider", providerService);
    }


    private WxCpMessageRouter newRouter(WxCpService wxCpService) {
        val newRouter = new WxCpMessageRouter(wxCpService);
        // 记录所有事件的日志 （异步执行）
        newRouter.rule().handler(SpringUtil.getBean(LogHandler.class)).next();

        // 自定义菜单事件
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxConsts.MenuButtonType.CLICK).handler(SpringUtil.getBean(MenuHandler.class)).end();

        // 点击菜单链接事件（这里使用了一个空的处理器，可以根据自己需要进行扩展）
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxConsts.MenuButtonType.VIEW).handler(SpringUtil.getBean(NullHandler.class)).end();

        // 关注事件
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxConsts.EventType.SUBSCRIBE).handler(SpringUtil.getBean(SubscribeHandler.class))
//                .end();

        // 取消关注事件
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxConsts.EventType.UNSUBSCRIBE)
//                .handler(SpringUtil.getBean(UnsubscribeHandler.class)).end();

        // 上报地理位置事件
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxConsts.EventType.LOCATION).handler(SpringUtil.getBean(LocationHandler.class))
//                .end();

        // 接收地理位置消息
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
//                .handler(SpringUtil.getBean(LocationHandler.class)).end();

        // 扫码事件（这里使用了一个空的处理器，可以根据自己需要进行扩展）
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxConsts.EventType.SCAN).handler(SpringUtil.getBean(NullHandler.class)).end();

        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxCpConsts.EventType.CHANGE_CONTACT).handler(new ContactChangeHandler()).end();
//
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event(WxCpConsts.EventType.ENTER_AGENT).handler(new EnterAgentHandler()).end();

        newRouter.rule().async(false).matcher(wxCpXmlMessage -> {
            Object infoType = wxCpXmlMessage.getAllFieldsMap().get("InfoType");
            return infoType != null && WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT.equalsIgnoreCase(infoType.toString());
        }).handler(new ExternalChangeHandler()).end();

        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxCpConsts.EventType.CHANGE_EXTERNAL_CHAT).handler(new ChatChangeHandler()).end();
        //客服
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event("kf_msg_or_event").handler(new KFmsgHandler()).end();

        // SuiteTicket 推送事件
//        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
//                .event("suite_ticket").handler(SpringUtil.getBean(MenuHandler.class)).end();

        // 默认
//        newRouter.rule().async(false).handler(SpringUtil.getBean(MsgHandler.class)).end();

        return newRouter;
    }
}
